#!/usr/bin/python
#
# Copyright (C) 2009 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


__author__ = 'e.bidelman (Eric Bidelman)'

import cgi
import os
import pickle
import logging
import atom.url
import gdata.auth
import gdata.docs
import gdata.docs.service
import gdata.contacts
import gdata.contacts.service
import gdata.alt.appengine

#from appengine_utilities.sessions import Session
from django.utils import simplejson
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.runtime import DeadlineExceededError
import liveboarddb 

SETTINGS = {
  'APP_NAME': 'LiveBoard v1',
  'CONSUMER_KEY': 'live-board.appspot.com',
  'SIG_METHOD': gdata.auth.OAuthSignatureMethod.RSA_SHA1,
  'SCOPES': ['http://docs.google.com/feeds/', 'http://www.google.com/m8/feeds/']
  }

f = open('rsakey.pem')
RSA_KEY = f.read()
f.close()

gdocs = gdata.docs.service.DocsService(source=SETTINGS['APP_NAME'])
gdocs.SetOAuthInputParameters(SETTINGS['SIG_METHOD'], SETTINGS['CONSUMER_KEY'],
                              rsa_key=RSA_KEY)
gdata.alt.appengine.run_on_appengine(gdocs)

gcontacts = gdata.contacts.service.ContactsService(source=SETTINGS['APP_NAME'])
gcontacts.SetOAuthInputParameters(SETTINGS['SIG_METHOD'], SETTINGS['CONSUMER_KEY'],
                              rsa_key=RSA_KEY)
gdata.alt.appengine.run_on_appengine(gcontacts)


class MainPage(webapp.RequestHandler):
  # GET /
  def get(self):
    self.redirect("/index.html")


class Login(webapp.RequestHandler):
  """Main page displayed to user."""

  # GET /login
  def get(self):

    user = users.get_current_user()
    gid = self.request.get('gid')
    if gid:
      path = "/index.html?gid=%s" % gid
    else:
      path = "/index.html"

    """
    res = db.GqlQuery("SELECT * FROM TokenCollection")
    for r in res:
      p = pickle.loads(r.pickled_tokens)
      logging.info("r = %s<br>", p)
    """ 

    if not user:
      self.response.out.write("Not signed in ")
      self.response.out.write('<a href="%s" class="ui-widget">Sign In</a>' % (
                                  users.create_login_url(path)))
    else:
      self.response.out.write('Hello, %s ' % (user.nickname()))
      self.response.out.write('<a href="%s" class="ui-widget">Sign Out</a>' % (
                                  users.create_logout_url(path)))


      #save the user in the db
      q = db.GqlQuery("SELECT * FROM UserInfo WHERE email = :1", user.email())
      r = q.fetch(1)

      if len(r) == 1:
        ui = r[0]
      else:
        ui = liveboarddb.UserInfo()

      ui.user = user
      ui.uid = 0
      ui.name = user.nickname()
      ui.email = user.email()
      db.put(ui)


class OAuthDance(webapp.RequestHandler):
  """Handler for the 3 legged OAuth dance, v1.0a."""
  """This handler is responsible for fetching an initial OAuth request token,
  redirecting the user to the approval page.  When the user grants access, they
  will be redirected back to this GET handler and their authorized request token
  will be exchanged for a long-lived access token."""

  # GET /get_oauth_token
  def get(self):

    gid = self.request.get('gid')
    if gid:
      path = "/index.html?gid=%s" % gid
    else:
      path = "/index.html"

    logging.info("OAuthDance: req.uri %s", self.request.uri)
    oauth_token = gdata.auth.OAuthTokenFromUrl(self.request.uri)
    if oauth_token:
      oauth_token.oauth_input_params = gcontacts.GetOAuthInputParameters()
      logging.info("oauth_input_params %s", oauth_token.oauth_input_params)
      gcontacts.SetOAuthToken(oauth_token)

      # 3.) Exchange the authorized request token for an access token
      oauth_verifier = self.request.get('oauth_verifier', default_value='')

      access_token = gcontacts.UpgradeToOAuthAccessToken(oauth_verifier=oauth_verifier)

      # Remember the access token in the current user's token store
      if access_token and users.get_current_user():
        gcontacts.token_store.add_token(access_token)
      elif access_token:
        gcontacts.current_token = access_token
        gcontacts.SetOAuthToken(access_token)

      self.redirect(path)

    else: 
      if users.get_current_user():
        # 1.) REQUEST TOKEN STEP. Provide the data scope(s) and the page we'll
        # be redirected back to after the user grants access on the approval page.
        req_token = gcontacts.FetchOAuthRequestToken(
            scopes=SETTINGS['SCOPES'], oauth_callback=self.request.uri)

        # Generate the URL to redirect the user to.  Add the hd paramter for a
        # better user experience.  Leaving it off will give the user the choice
        # of what account (Google vs. Google Apps) to login with.
        domain = self.request.get('domain', default_value='default')
        approval_page_url = gcontacts.GenerateOAuthAuthorizationURL(
            extra_params={'hd': domain})

        # 2.) APPROVAL STEP.  Redirect to user to Google's OAuth approval page.
        self.redirect(approval_page_url)
      else:
        self.redirect(path)


class RevokeToken(webapp.RequestHandler):

  # GET /revoke_token
  def get(self):
    """Revokes the current user's OAuth access token."""

    try:
      gcontacts.RevokeOAuthToken()
    except (gdata.service.RevokingOAuthTokenFailed, gdata.service.NonOAuthToken):
      logging.info("RevokeToken failed")
      pass

    gcontacts.token_store.remove_all_tokens()

  
class FetchData(RevokeToken):
  """Fetches the user's data."""

  def getContacts(self, query='', path='/get_oauth_token'):
    obj = {}
    data = []

    if query:
      uri = gcontacts.GetFeedUri()+"?%s" % (query)
    else:
      uri = gcontacts.GetFeedUri()

    query = gdata.contacts.service.ContactsQuery()
    query.max_results = 500
    logging.info('Feed url: %s' % query.ToUri())
    logging.info("getContacts: uri=%s", uri)

    try:
      obj['msg'] = "Success"
      feed = gcontacts.GetContactsFeed(query.ToUri())
      for e in feed.entry:
          for em in e.email:
              if em.primary and em.primary == "true":
                  contact = {}
                  contact['name'] = e.title.text
                  contact['email'] = em.address
                  data.append(contact)
      obj['data'] = data
    except gdata.service.RequestError, request_error:
      obj['msg'] = 'Authorize'
      obj['data'] = []
      obj['data'].append("<a href='%s' class='ui-widget'>Authorize</a>" % (
                          path))

      #RevokeToken.get(self)
      logging.error("fetch_data: RequestError")
      logging.error("fetch_data: send authorization request %s" % (path))
    except DeadlineExceededError:
      self.response.clear()
      self.response.set_status(500)
      self.response.out.write("This operation could not be completed in time...")

    jsonstr = simplejson.dumps(obj)
    self.response.out.write(jsonstr)


  def getDocs(self):
    obj = {}
    json = []
    try:
      feed = gdocs.GetDocumentListFeed()
      for entry in feed.entry:
        if entry.lastModifiedBy is not None:
          last_modified_by = entry.lastModifiedBy.email.text
        else:
          last_modified_by = ''
        if entry.lastViewed is not None:
          last_viewed = entry.lastViewed.text
        else:
          last_viewed = ''
        json.append({'title': entry.title.text,
                     'links': {'alternate': entry.GetHtmlLink().href},
                     'published': entry.published.text,
                     'updated': entry.updated.text,
                     'resourceId': entry.resourceId.text,
                     'type': entry.GetDocumentType(),
                     'lastModifiedBy': last_modified_by,
                     'lastViewed': last_viewed
                    })
      obj['msg'] = 'Success'
      obj['data'] = json
    except gdata.service.RequestError, error:
      obj['msg'] = 'Authorize'
      obj['data'] = []
      obj['data'].append("<a href='/get_oauth_token'>Authorize</a>")

      #RevokeToken.get(self)
      logging.error("fetch_data: RequestError")
    except DeadlineExceededError:
      self.response.clear()
      self.response.set_status(500)
      self.response.out.write("This operation could not be completed in time...")

    self.response.out.write(simplejson.dumps(obj))

  # GET /fetch
  def get(self):
    service = self.request.get('service')
    query = self.request.get('q')
    gid = self.request.get('gid')
    if gid:
      path = "/get_oauth_token?gid=%s" % gid
    else:
      path = "/get_oauth_token"

    if service == "contacts":
      self.getContacts(query, path)
    elif service == "docs":
      self.getDocs()

def main():
  application = webapp.WSGIApplication([('/', MainPage),
                                        ('/login', Login),
                                        ('/get_oauth_token', OAuthDance),
                                        ('/fetch', FetchData),
                                        ('/revoke_token', RevokeToken)],
                                        debug=True)
  run_wsgi_app(application)

